<script setup>
  import { computed, onMounted, ref, watch } from 'vue'
  import hljs from 'highlight.js'
  import 'highlight.js/styles/vs.css'
  import { marked } from 'marked'
  import 'github-markdown-css/github-markdown-light.css'

  const props = defineProps({
    modelValue: Boolean,
    fileUrl: String,
    fileName: String
  })

  const emit = defineEmits(['update:modelValue'])
  const content = ref('')
  const loading = ref(false)
  const lineCount = ref(0)
  const isMd = computed(() => props.fileName?.toLowerCase().endsWith('.md'))

  const dialogVisible = computed({
    get: () => props.modelValue,
    set: value => emit('update:modelValue', value)
  })

  const getLanguage = fileName => {
    const ext = fileName.split('.').pop()?.toLowerCase() || ''
    const languageMap = {
      js: 'javascript',
      ts: 'typescript',
      py: 'python',
      java: 'java',
      cpp: 'cpp',
      c: 'c',
      cs: 'csharp',
      php: 'php',
      sql: 'sql',
      html: 'html',
      css: 'css',
      json: 'json',
      xml: 'xml',
      yaml: 'yaml',
      md: 'markdown',
      sh: 'bash',
      vue: 'xml'
    }
    return languageMap[ext] || 'plaintext'
  }

  marked.setOptions({
    highlight: function (code, lang) {
      const language = hljs.getLanguage(lang) ? lang : 'plaintext'
      return hljs.highlight(code, { language }).value
    },
    breaks: true
  })

  const loadContent = async () => {
    if (!props.fileUrl) return

    loading.value = true
    try {
      const response = await fetch(props.fileUrl)
      const text = await response.text()

      if (isMd.value) {
        content.value = marked(text)
      } else {
        const language = getLanguage(props.fileName)
        content.value =
          language !== 'plaintext'
            ? hljs.highlight(text, { language, ignoreIllegals: true }).value
            : text
      }

      lineCount.value = text.split('\n').length
    } catch (error) {
      console.error('Failed to load file:', error)
    } finally {
      loading.value = false
    }
  }

  watch(() => props.fileUrl, loadContent)

  onMounted(() => {
    if (props.fileUrl) loadContent()
  })

  const resetContent = () => {
    content.value = ''
    lineCount.value = 0
  }

  watch(
    () => dialogVisible.value,
    newVal => {
      if (!newVal) {
        resetContent()
      }
    }
  )
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    :title="fileName"
    class="text-preview-dialog"
    destroy-on-close
    width="80%"
    @closed="resetContent"
  >
    <div v-loading="loading" class="editor-container">
      <template v-if="isMd">
        <div class="markdown-container markdown-body" v-html="content"></div>
      </template>
      <template v-else>
        <div class="line-numbers">
          <template v-for="i in lineCount" :key="i">
            <div class="line-number">{{ i }}</div>
          </template>
        </div>
        <pre class="content"><code v-html="content"></code></pre>
      </template>
    </div>
  </el-dialog>
</template>

<style lang="less" scoped>
  .text-preview-dialog {
    :deep(.el-dialog__body) {
      padding: 0;
      background: #ffffff;
    }

    :deep(.el-dialog__header) {
      background: #ffffff;
      margin: 0;
      padding: 12px 20px;
      border-bottom: 1px solid #e4e7ed;
    }

    :deep(.el-dialog) {
      background: #ffffff;
    }
  }

  .editor-container {
    display: flex;
    height: 60vh;
    background: #ffffff;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 14px;
    line-height: 1.5;
    overflow: hidden;

    .markdown-container {
      flex: 1;
      overflow: auto;
      padding: 24px;
    }

    .line-numbers {
      padding: 10px 8px;
      background: #f5f5f5;
      border-right: 1px solid #dcdfe6;
      text-align: right;
      user-select: none;
      overflow-y: hidden;

      .line-number {
        color: #909399;
        padding-right: 4px;
      }
    }

    .content {
      flex: 1;
      margin: 0;
      padding: 10px;
      overflow: auto;
      background: #ffffff;

      code {
        font-family: inherit;
        white-space: pre;
      }
    }
  }

  :deep(.markdown-body) {
    pre code {
      white-space: pre;
    }
  }

  .content::-webkit-scrollbar,
  .markdown-body::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  .content::-webkit-scrollbar-thumb,
  .markdown-body::-webkit-scrollbar-thumb {
    background: #c0c4cc;
    border-radius: 4px;
  }

  .content::-webkit-scrollbar-track,
  .markdown-body::-webkit-scrollbar-track {
    background: #f5f5f5;
  }
</style>
